package org.demo.szml.userservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.apache.shardingsphere.transaction.core.TransactionTypeHolder;
import org.demo.szml.api.dto.PermissionBindingReqDTO;
import org.demo.szml.api.dto.PermissionBindingResDTO;
import org.demo.szml.api.dto.PermissionUserAttributionResDTO;
import org.demo.szml.api.response.Response;
import org.demo.szml.api.response.ResponseCode;
import org.demo.szml.api.rpc.IPermissionRPCService;
import org.demo.szml.eventtype.converter.logging.LoggingEventDetailConverter;
import org.demo.szml.eventtype.event.logging.LoggingActionType;
import org.demo.szml.eventtype.event.logging.LoggingEvent;
import org.demo.szml.userservice.aop.annotation.LoggableAction;
import org.demo.szml.userservice.controller.dto.*;
import org.demo.szml.userservice.producer.LoggingMessageProducer;
import org.demo.szml.userservice.repository.IUserRepository;
import org.demo.szml.userservice.repository.po.UsersPO;
import org.demo.szml.userservice.service.IUserService;
import org.demo.szml.userservice.service.result.UserInfoHandleResult;
import org.demo.szml.userservice.service.result.UserLoginHandleResult;
import org.demo.szml.userservice.service.result.UserModifyInfoHandleResult;
import org.demo.szml.userservice.service.result.UserRegisterHandleResult;
import org.demo.szml.userservice.utils.Argon2Util;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @description: 用户服务实现类
 * @date: 2025/6/15 22:52
 * @version: 1.0
 */
@Service
public class UserServiceImpl implements IUserService {

    private final IUserRepository userRepository;

    private final LoggingMessageProducer loggingMessageProducer;

    private final IPermissionRPCService permissionService;

    public UserServiceImpl(IUserRepository userRepository,
                           LoggingMessageProducer loggingMessageProducer,
                           IPermissionRPCService permissionService){
        this.userRepository = userRepository;
        this.loggingMessageProducer = loggingMessageProducer;
        this.permissionService = permissionService;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class,name = "user-service-at-group")
//    @Transactional
//    @ShardingTransactionType(TransactionType.BASE)
    @LoggableAction(actionType = LoggingActionType.REGISTER)
    public UserRegisterHandleResult register(UserRegisterDTO registerDTO) {
        TransactionTypeHolder.set(TransactionType.BASE);
        System.out.println(RootContext.getXID());
        UserRegisterHandleResult handleResult = new UserRegisterHandleResult();
        UsersPO user = this.buildUserPO(registerDTO);
        //插入新用户
        Long userId = userRepository.saveNewUser(user);
        //rpc调用绑定默认权限 - 普通用户
        Response<PermissionBindingResDTO> bindResponse = permissionService.bindDefaultRole(userId);
        //权限绑定失败 则返回提示信息
        if (!ResponseCode.SUCCESS.equals(bindResponse.getCode())){
            handleResult.setHandleSuccess(false);
            handleResult.setExtInfo(bindResponse.getInfo());
            return handleResult;
        }
        handleResult.setUserId(userId);
        System.out.println(RootContext.getXID());
        return handleResult;
    }

    @Override
    @LoggableAction(actionType = LoggingActionType.LOGIN)
    public UserLoginHandleResult login(UserLoginDTO userLoginDTO) {
        UserLoginHandleResult handleResult = new UserLoginHandleResult();
        //查验密码
        UsersPO usersPO = userRepository.selectUserPassword(userLoginDTO.getUsername());
        if(Objects.isNull(usersPO)){
            handleResult.setHandleSuccess(false);
            handleResult.setExtInfo("用户不存在");
            return handleResult;
        }
        //利用工具类验证加密后密码
        boolean verify = Argon2Util.verify(usersPO.getPassword(), userLoginDTO.getPassword());
        if(!verify){
            handleResult.setHandleSuccess(false);
            handleResult.setExtInfo("密码错误");
            return handleResult;
        }
        handleResult.setUserId(usersPO.getUserId());
        return handleResult;
    }

    @Override
    @LoggableAction(actionType = LoggingActionType.SELECT_USER_BASE_INFO)
    public UserInfoHandleResult selectUserById(UserSelectDTO userSelectDTO) {
        Long operatorId = userSelectDTO.getOperatorId();
        Long userId = userSelectDTO.getUserId();
        //验证是否存在操作的权限
        Response<PermissionUserAttributionResDTO> permissionResult = permissionService.authAttributeUser(operatorId, userId);
        //如果RPC调用成功
        if(permissionResult.getCode().equals(ResponseCode.SUCCESS)){
            PermissionUserAttributionResDTO data = permissionResult.getData();
            //验证是否存在操作权限
            if(data.getHandleResult() && data.getUserIds().contains(userId)){
                List<UsersPO> usersPOs = userRepository.getUserInfoById(Collections.singletonList(userId));
                if(ObjectUtils.isEmpty(usersPOs)){
                    UserInfoHandleResult userInfoHandleResult = new UserInfoHandleResult();
                    userInfoHandleResult.setHandleSuccess(false);
                    userInfoHandleResult.setExtInfo("没有要查询的用户信息");
                    return userInfoHandleResult;
                }
                UsersPO usersPO = usersPOs.get(0);
                return UserInfoHandleResult.builder().userId(usersPO.getUserId())
                        .username(usersPO.getUsername())
                        .phone(usersPO.getPhone())
                        .email(usersPO.getEmail())
                        .build();
            }
        }
        //RPC调用失败 则返回失败信息
        UserInfoHandleResult userInfoHandleResult = new UserInfoHandleResult();
        userInfoHandleResult.setExtInfo(permissionResult.getInfo());
        userInfoHandleResult.setHandleSuccess(false);
        return userInfoHandleResult;
    }

    @Override
    @LoggableAction(actionType = LoggingActionType.SELECT_USER_BASE_INFO)
    public Page<UserInfoHandleResult> pageUsers(UserSelectDTO userSelectDTO) {
        Long operatorId = userSelectDTO.getOperatorId();
        Integer page = userSelectDTO.getPage();
        Integer size = userSelectDTO.getSize();
        //验证权限信息
        Response<PermissionUserAttributionResDTO> permissionResult = permissionService.authAttributeUsers(operatorId, page, size);
        //如果RPC调用成功
        if (permissionResult.getCode().equals(ResponseCode.SUCCESS)) {
            PermissionUserAttributionResDTO data = permissionResult.getData();
            List<Long> userIds = data.getUserIds();
            if(!ObjectUtils.isEmpty(userIds)){
                List<UsersPO> userInfoById = userRepository.getUserInfoById(userIds);
                Page<UserInfoHandleResult> resultPage = new Page<>();
                resultPage.setTotal(data.getTotal());
                resultPage.setRecords(userInfoById.stream().map(userInfo -> UserInfoHandleResult.builder()
                        .userId(userInfo.getUserId())
                        .username(userInfo.getUsername())
                        .phone(userInfo.getPhone())
                        .email(userInfo.getEmail())
                        .build()).collect(Collectors.toList()));
                return resultPage;
            }
        }
        //返回空信息
        return Page.of(page,size,0);
    }

    @Override
    @LoggableAction(actionType = LoggingActionType.MODIFY_USER_BASE_INFO)
    public UserModifyInfoHandleResult modifyUserInfo(UserModifyInfoDTO modifyInfo) {
        Long operatorId = modifyInfo.getOperatorId();
        Long userId = modifyInfo.getUserId();
        Response<PermissionUserAttributionResDTO> permissionResult = permissionService.authAttributeUser(operatorId, userId);
        if(ResponseCode.SUCCESS.equals(permissionResult.getCode())){
            //存在合法权限才可以修改
            UsersPO user = buildUserPO(userId, modifyInfo);
            int update = userRepository.modifyUserInfo(user);
            if(update > 0){
                LoggingEvent.LoggingEventInfo modify = LoggingEvent.LoggingEventInfo.builder().action("MODIFY")
                        .ip(modifyInfo.getClientIp()).detail(JSON.toJSONString(modifyInfo))
                        .userId(userId).build();
                loggingMessageProducer.sendLoggingMessage(modify);
                return new UserModifyInfoHandleResult();
            }else{
                UserModifyInfoHandleResult handleResult = new UserModifyInfoHandleResult();
                handleResult.setExtInfo("修改信息时写入失败! 请反馈");
                return handleResult;
            }
        }
        UserModifyInfoHandleResult handleResult = new UserModifyInfoHandleResult();
        handleResult.setHandleSuccess(false);
        handleResult.setExtInfo(permissionResult.getInfo());
        return handleResult;
    }

    @Override
    @LoggableAction(actionType = LoggingActionType.MODIFY_USER_BASE_INFO)
    public UserModifyInfoHandleResult resetPassword(UserResetPwdDTO resetPwdDTO) {
        Long operatorId = resetPwdDTO.getOperatorId();
        Long userId = resetPwdDTO.getUserId();
        Response<PermissionUserAttributionResDTO> permissionResult = permissionService.authAttributeUser(operatorId, userId);
        if(ResponseCode.SUCCESS.equals(permissionResult.getCode())){
            UsersPO user = buildUserPO(userId, resetPwdDTO);
            int update = userRepository.modifyUserInfo(user);
            if(update > 0){
                return new UserModifyInfoHandleResult();
            }else{
                UserModifyInfoHandleResult handleResult = new UserModifyInfoHandleResult();
                handleResult.setExtInfo("修改信息时写入失败! 请反馈");
                return handleResult;
            }
        }
        UserModifyInfoHandleResult handleResult = new UserModifyInfoHandleResult();
        handleResult.setHandleSuccess(false);
        handleResult.setExtInfo(permissionResult.getInfo());
        return handleResult;
    }

    @Override
    @LoggableAction(actionType = LoggingActionType.MODIFY_USER_ROLE_INFO)
    public UserModifyInfoHandleResult rebindRole(UserRebindDTO rebindDTO) {
        Long operatorId = rebindDTO.getOperatorId();
        Long userId = rebindDTO.getUserId();
        UserModifyInfoHandleResult modifyResult = new UserModifyInfoHandleResult();
        if(operatorId.equals(userId)){
            modifyResult.setHandleSuccess(false);
            modifyResult.setExtInfo("不能修改自己的权限");
            return modifyResult;
        }
        Response<PermissionBindingResDTO> bindingResult = permissionService.rebindRole(userId, operatorId, rebindDTO.getRoleId());
        modifyResult.setHandleSuccess(bindingResult.getCode().equals(ResponseCode.SUCCESS));
        modifyResult.setExtInfo(bindingResult.getInfo());
        return modifyResult;
    }


    private UsersPO buildUserPO(Long userId, UserResetPwdDTO resetPwdDTO) {
        UsersPO user = new UsersPO();
        user.setUserId(userId);
        user.setPassword(Argon2Util.encrypt(resetPwdDTO.getPassword()));
        return user;
    }

    private UsersPO buildUserPO(Long userId, UserModifyInfoDTO modifyInfo) {
        UsersPO user = new UsersPO();
        user.setUsername(modifyInfo.getNewUsername());
        user.setUserId(userId);
        return user;
    }


    private UsersPO buildUserPO(UserRegisterDTO registerDTO){
        //对密码进行加密操作
        UsersPO user = new UsersPO();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(Argon2Util.encrypt(registerDTO.getPassword()));
        user.setEmail(registerDTO.getEmail());
        user.setPhone(registerDTO.getPhone());
        return user;
    }
}
